package net.lastcoder.ifserver.util;

import net.lastcoder.ifserver.cache.Cache;
import net.lastcoder.ifserver.cache.CacheFactory;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**缓存工具
 * auth: WenYF
 * date: 2017/8/11
 */
public class CacheHelper {
    protected static final Logger Log = LoggerFactory.getLogger(CacheHelper.class);

    private static JedisPool sJedisPool;

    private static Jedis getJedis() {
        if (sJedisPool == null) {
            loadJedisConnection();
        }

        return sJedisPool.getResource();
    }

    private static void loadJedisConnection() {
        JedisPoolConfig config = new JedisPoolConfig();

        //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
        config.setBlockWhenExhausted(true);

        //设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
        config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");

        //是否启用pool的jmx管理功能, 默认true
        config.setJmxEnabled(true);

        //MBean ObjectName = new ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name=" + "pool" + i); 默 认为"pool", JMX不熟,具体不知道是干啥的...默认就好.
        config.setJmxNamePrefix("pool");

        //是否启用后进先出, 默认true
        config.setLifo(true);

        //最大空闲连接数, 默认8个
        config.setMaxIdle(32);

        //最大连接数, 默认8个
        config.setMaxTotal(128);

        //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
        config.setMaxWaitMillis(10000);

        //逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
        config.setMinEvictableIdleTimeMillis(1800000);

        //最小空闲连接数, 默认0
        config.setMinIdle(0);

        //每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        config.setNumTestsPerEvictionRun(10);

        //对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)
        config.setSoftMinEvictableIdleTimeMillis(1800000);

        //在获取连接的时候检查有效性, 默认false
        config.setTestOnBorrow(false);

        //在空闲时检查有效性, 默认false
        config.setTestWhileIdle(false);

        //逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        config.setTimeBetweenEvictionRunsMillis(600000);
        sJedisPool = new JedisPool(config, "", 6379, 10000, "");
    }

    public static Jedis obtainJedis() {
        return getJedis();
    }


    public static void hSet(String key, String field, String value) {
        // 加头tag主要是为了可能造成的键值混乱
        key = "xy." + key;
        Jedis jedis = getJedis();
        jedis.hset(key, field, value);
        jedis.close();
    }


    public static String hGet(String key, String field) {
        long t1 = System.currentTimeMillis();
        key = "xy." + key;
        Jedis jedis = getJedis();
        String ret = jedis.hget(key, field);
        jedis.close();
        Log.debug("hGet " + key + " time : " + (System.currentTimeMillis() - t1));
        return ret;
    }

    public static Map<String, String> hGet(String key) {
        long t1 = System.currentTimeMillis();
        key = "xy." + key;
        Jedis jedis = getJedis();
        Map<String, String> ret = jedis.hgetAll(key);
        jedis.close();
        Log.debug("hGet " + key + " time : " + (System.currentTimeMillis() - t1));
        return ret;
    }

    private static Cache<String, JSONObject> caches = CacheFactory.createLocalCache("xy.team");

    public static JSONObject getTeam(String tid, String channel) {
        String key = channel + "." + tid;
        return caches.get(key);
    }

    public static void setTeam(String tid, String channel, JSONObject teamJson) {
        String key = channel + "." + tid;
        caches.put(key, teamJson);
    }


    public static void deleteTeam(String tid, String channel) {
        String key = channel + "." + tid;
        caches.remove(key);
    }

    public static void set(String key, String o, int second) {
        // 加头tag主要是为了可能造成的键值混乱
        key = "xy." + key;
        Jedis jedis = getJedis();
        jedis.setex(key, second, o);
        jedis.close();
    }

    public static void set(String key, String o) {
        // 加头tag主要是为了可能造成的键值混乱
        key = "xy." + key;
        Jedis jedis = getJedis();
        jedis.set(key, o);
        jedis.close();
    }

//    public static void setex(String key, int seconds, String value) {
//        key = "xy." + key;
//        Jedis jedis = getJedis();
//        jedis.setex(key, seconds, value);
//        jedis.close();
//    }

    public static void remove(String key) {
        key = "xy." + key;
        Jedis jedis = getJedis();
        jedis.del(key);
        jedis.close();
    }

    public static String get(String key) {
        long t1 = System.currentTimeMillis();
        key = "xy." + key;
        Jedis jedis = getJedis();
        String ret = jedis.get(key);
        jedis.close();
        Log.debug("get " + key + " time : " + (System.currentTimeMillis() - t1));
        return ret;
    }

    /**得到list的集合数量
     * @param key
     * @return
     */
    public static long getListSize(String key) {
        long t1 = System.currentTimeMillis();
        key = "xy.list." + key;
        Jedis jedis = getJedis();
        long size = jedis.llen(key);
        jedis.close();
        Log.debug("getListSize " + key + " time : " + (System.currentTimeMillis() - t1));
        return size;
    }

    /**
     * 给一个list添加元素
     * @param key key
     * @param str 数据
     * @return  添加数据后的长度
     */
    public static long addList(String key, String... str) {
        key = "xy.list." + key;
        Jedis jedis = getJedis();
        long size = jedis.lpush(key, str);
        jedis.close();
        return size;
    }

    /**移出头元素
     * @param key key
     * @param count    需要移出的数量
     * @return 还剩多少元素
     */
    public static long removeList(String key, long count) {
        key = "xy.list." + key;
        Jedis jedis = getJedis();
        for (int i = 0; i < count; i++) {
            jedis.rpop(key);
        }
        long size = jedis.llen(key);
        jedis.close();

        return size;
    }

    /**从尾部开始   see {@link Jedis#lrange(String, long, long)}
     * @param key key
     * @param start
     * @param end
     * @return 集合
     */
    public static List<String> getLists(String key, int start, int end) {
        key = "xy.list." + key;
        Jedis jedis = getJedis();
        List<String> lists = jedis.lrange(key, start, end);
        jedis.close();
        return lists;
    }

    public static void removeList(String key) {
        key = "xy.list." + key;
        Jedis jedis = getJedis();
        jedis.del(key);
        jedis.close();
    }
}
